﻿#pragma once

#include "../MirObjects/Effect.h"
#include "../MirObjects/Frames.h"
#include <string>
#include <vector>
#include <stdexcept>
#include "../../tangible_filesystem.h"

//C# TO C++ CONVERTER NOTE: Forward class declarations:
namespace Client::MirGraphics { class MLibrary; }
namespace Client::MirGraphics { class MImage; }

using namespace SlimDX;
using namespace SlimDX::Direct3D9;
using namespace Client::MirObjects;

namespace Client::MirGraphics
{
    class Libraries final
    {
    public:
        static bool Loaded;
        static int Count;
        static int Progress;

        static MLibrary *const ChrSel;
        static MLibrary *const Prguse;
        static MLibrary *const Prguse2;
        static MLibrary *const Prguse3;
        static MLibrary *const BuffIcon;
        static MLibrary *const Help;
        static MLibrary *const MiniMap;
        static MLibrary *const Title;
        static MLibrary *const MagIcon;
        static MLibrary *const MagIcon2;
        static MLibrary *const Magic;
        static MLibrary *const Magic2;
        static MLibrary *const Magic3;
        static MLibrary *const Effect;
        static MLibrary *const MagicC;
        static MLibrary *const GuildSkill;

        static MLibrary *const Background;


        static MLibrary *const Dragon;

        //Map
        static const std::vector<MLibrary*> MapLibs;

        //Items
        static MLibrary *const Items;
        static MLibrary *const StateItems;
        static MLibrary *const FloorItems;

        //Deco
        static MLibrary *const Deco;

        static std::vector<MLibrary*> CArmours;
        static std::vector<MLibrary*> CWeapons;
        static std::vector<MLibrary*> CWeaponEffect;
        static std::vector<MLibrary*> CHair;
        static std::vector<MLibrary*> CHumEffect;
        static std::vector<MLibrary*> AArmours;
        static std::vector<MLibrary*> AWeaponsL;
        static std::vector<MLibrary*> AWeaponsR;
        static std::vector<MLibrary*> AHair;
        static std::vector<MLibrary*> AHumEffect;
        static std::vector<MLibrary*> ARArmours;
        static std::vector<MLibrary*> ARWeapons;
        static std::vector<MLibrary*> ARWeaponsS;
        static std::vector<MLibrary*> ARHair;
        static std::vector<MLibrary*> ARHumEffect;
        static std::vector<MLibrary*> Monsters;
        static std::vector<MLibrary*> Gates;
        static std::vector<MLibrary*> Flags;
        static std::vector<MLibrary*> Mounts;
        static std::vector<MLibrary*> NPCs;
        static std::vector<MLibrary*> Fishing;
        static std::vector<MLibrary*> Pets;
        static std::vector<MLibrary*> Transform;
        static std::vector<MLibrary*> TransformMounts;
        static std::vector<MLibrary*> TransformEffect;
        static std::vector<MLibrary*> TransformWeaponEffect;

    private:
        class StaticConstructor
        {
        public:
            StaticConstructor();
        };

    private:
        static Libraries::StaticConstructor staticConstructor;


        static void InitLibrary(std::vector<MLibrary*> &library, const std::string &path, const std::string &toStringValue, const std::string &suffix = "");

        static void LoadLibraries();

        static void LoadGameLibraries();

    };

    class MLibrary final
    {
    public:
        static const std::string Extention;
        static constexpr int LibVersion = 3;

    private:
        const std::string _fileName;

        std::vector<MImage*> _images;
        FrameSet *_frames;
        std::vector<int> _indexList;
        int _count = 0;
        bool _initialized = false;

        BinaryReader *_reader;
        FileStream *_fStream;

    public:
        virtual ~MLibrary()
        {
            delete _frames;
            delete _reader;
            delete _fStream;
        }

        FrameSet *getFrames() const;

        MLibrary(const std::string &filename);

        void Initialize();

    private:
        bool CheckImage(int index);

    public:
        Point *GetOffSet(int index);
        Size *GetSize(int index);
        Size *GetTrueSize(int index);

        void Draw(int index, int x, int y);
        void Draw(int index, Point *point, Color *colour, bool offSet = false);

        void Draw(int index, Point *point, Color *colour, bool offSet, float opacity);

        void DrawBlend(int index, Point *point, Color *colour, bool offSet = false, float rate = 1);
        void Draw(int index, Rectangle *section, Point *point, Color *colour, bool offSet);
        void Draw(int index, Rectangle *section, Point *point, Color *colour, float opacity);
        void Draw(int index, Point *point, Size *size, Color *colour);

        void DrawTinted(int index, Point *point, Color *colour, Color *Tint, bool offSet = false);

        void DrawUp(int index, int x, int y);
        void DrawUpBlend(int index, Point *point);

        bool VisiblePixel(int index, Point *point, bool accuate);
    };

    class MImage final
    {
    public:
        short Width = 0, Height = 0, X = 0, Y = 0, ShadowX = 0, ShadowY = 0;
        unsigned char Shadow = 0;
        int Length = 0;

        bool TextureValid = false;
        Texture *Image;
        //layer 2:
        short MaskWidth = 0, MaskHeight = 0, MaskX = 0, MaskY = 0;
        int MaskLength = 0;

        Texture *MaskImage;
        bool HasMask = false;

        long long CleanTime = 0;
        Size *TrueSize;

//C# TO C++ CONVERTER TODO TASK: C# 'unsafe' code is not converted by C# to C++ Converter:
//        public unsafe byte * Data;

        virtual ~MImage()
        {
            delete Image;
            delete MaskImage;
            delete TrueSize;
            delete byte;
        }

        MImage(BinaryReader *reader);

//C# TO C++ CONVERTER TODO TASK: C# 'unsafe' code is not converted by C# to C++ Converter:
//        public unsafe void CreateTexture(BinaryReader reader)
//        {
//            int w = Width; // + (4 - Width % 4) % 4;
//            int h = Height; // + (4 - Height % 4) % 4;
//
//            Image = new Texture(DXManager.Device, w, h, 1, Usage.None, Format.A8R8G8B8, Pool.Managed);
//            DataRectangle stream = Image.LockRectangle(0, LockFlags.Discard);
//            Data = (byte * )stream.Data.DataPointer;
//
//            byte[] decomp = DecompressImage(reader.ReadBytes(Length));
//
//            stream.Data.Write(decomp, 0, decomp.Length);
//
//            stream.Data.Dispose();
//            Image.UnlockRectangle(0);
//
//            if (HasMask)
//            {
//                reader.ReadBytes(12);
//                w = Width; // + (4 - Width % 4) % 4;
//                h = Height; // + (4 - Height % 4) % 4;
//
//                MaskImage = new Texture(DXManager.Device, w, h, 1, Usage.None, Format.A8R8G8B8, Pool.Managed);
//                stream = MaskImage.LockRectangle(0, LockFlags.Discard);
//
//                decomp = DecompressImage(reader.ReadBytes(Length));
//
//                stream.Data.Write(decomp, 0, decomp.Length);
//
//                stream.Data.Dispose();
//                MaskImage.UnlockRectangle(0);
//            }
//
//            DXManager.TextureList.Add(this);
//            TextureValid = true;
//
//            CleanTime = CMain.Time + Settings.CleanDelay;
//        }

//C# TO C++ CONVERTER TODO TASK: C# 'unsafe' code is not converted by C# to C++ Converter:
//        public unsafe void DisposeTexture()
//        {
//            DXManager.TextureList.Remove(this);
//
//            if (Image != nullptr && !Image.Disposed)
//            {
//                Image.Dispose();
//            }
//
//            if (MaskImage != nullptr && !MaskImage.Disposed)
//            {
//                MaskImage.Dispose();
//            }
//
//            TextureValid = false;
//            Image = nullptr;
//            MaskImage = nullptr;
//            Data = nullptr;
//        }

//C# TO C++ CONVERTER TODO TASK: C# 'unsafe' code is not converted by C# to C++ Converter:
//        public unsafe bool VisiblePixel(Point p)
//        {
//            if (p.X < 0 || p.Y < 0 || p.X >= Width || p.Y >= Height)
//                return false;
//
//            int w = Width;
//
//            bool result = false;
//            if (Data != nullptr)
//            {
//                int x = p.X;
//                int y = p.Y;
//
//                int index = (y * (w << 2)) + (x << 2);
//
//                byte col = Data[index];
//
//                if (col == 0)
//                    return false;
//                else
//                    return true;
//            }
//            return result;
//        }

        Size *GetTrueSize();

    private:
        static std::vector<unsigned char> DecompressImage(std::vector<unsigned char> &image);
    };
}
